/**************************************************************************************************
* Title: SumDoubleBufferedAllocator.h
* Author: Gael Huber
* Description: Implements a double-buffered allocator. This utilizes two stack allocators that are
*	switched between. This kind of allocator is very useful for performing asynchronous tasks. The
*	data stored on the ith frame must, however, be used before the i+2th frame.
**************************************************************************************************/
#ifndef __SUMDOUBLEBUFFEREDALLOCATOR_H__
#define __SUMDOUBLEBUFFEREDALLOCATOR_H__

#include "SumStackAllocator.h"

class DoubleBufferedAllocator {
public:
	// Constructs a double-buffered allocator of size n bytes
	inline explicit DoubleBufferedAllocator(size_t stackSize_bytes) 
	{
		// Allocate both stack allocators
		stacks[0] = new StackAllocator(stackSize_bytes);
		stacks[1] = new StackAllocator(stackSize_bytes);

		// First stack is the current stack
		currStack = 0;
	}

	// Destructor
	inline ~DoubleBufferedAllocator(void) 
	{
		delete stacks[0];
		delete stacks[1];
	}

	// Swap the stack buffers
	inline void swapBuffers(void)
	{
		currStack = (unsigned int) !currStack;
	}

	// Clear the current buffer
	inline void clearCurrentBuffer(void)
	{
		stacks[currStack]->clear();
	}

	// Allocate a given number of bytes
	inline void* alloc(size_t size_bytes)
	{
		return stacks[currStack]->alloc(size_bytes);
	}

	// Rolls the stack back to a previous marker.
	inline void freeToMarker(Marker marker)
	{
		stacks[currStack]->freeToMarker(marker);
	}

	// Rolls the stack back to a previous marker, but takes in a void* and does the explicit 
	// conversion within the bounds of the function.
	inline void freeToMarker(void* marker)
	{
		stacks[currStack]->freeToMarker(marker);
	}

private:
	unsigned int currStack;		// The current stack
	StackAllocator* stacks[2];	// Each buffer is a single stack allocator
};

// Overload new and delete for the benefit of the double-buffered allocator

// Overload new for syntactic ease-of-use (permits regular initialization/allocation of objects)
static inline void* operator new (size_t size, DoubleBufferedAllocator& dba)
{
	return dba.alloc(size);
}

// Overload new[] for syntactic ease-of-use (permits regular initialization/allocation of arrays)
static inline void* operator new[] (size_t size, DoubleBufferedAllocator& dba)
{
	return dba.alloc(size);
}

// Overload delete for syntactic ease-of-use (permits regular deletion of objects)
static inline void operator delete (void* mem, DoubleBufferedAllocator& dba)
{
	dba.freeToMarker((Marker)mem);
}

// Overload delete[] for syntactic ease-of-use (permits regular deletion of array objects
static inline void operator delete[] (void* mem, DoubleBufferedAllocator& dba)
{
	dba.freeToMarker((Marker)mem);
}

#endif